package com.shiku.imserver;

import com.shiku.imserver.common.ImSessionContext;
import com.shiku.imserver.common.tcp.TcpSessionContext;
import com.shiku.imserver.common.ws.WsSessionContext;

import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.core.ReadCompletionHandler;
import org.tio.core.Tio;
import org.tio.core.ssl.SslFacadeContext;
import org.tio.core.ssl.SslUtils;
import org.tio.server.AcceptCompletionHandler;
import org.tio.server.ServerGroupStat;
import org.tio.server.TioServer;
import org.tio.utils.SystemTimer;

public class ShikuAcceptCompletionHandler extends AcceptCompletionHandler {
    private static Logger log = LoggerFactory.getLogger(AcceptCompletionHandler.class);
    private AsynchronousServerSocketChannel serverSocketChannel;
    private byte protocol;

    public ShikuAcceptCompletionHandler(AsynchronousServerSocketChannel serverSocketChannel, byte protocol) {
        this.protocol = protocol;
        this.serverSocketChannel = serverSocketChannel;
    }

    @Override
    public void completed(AsynchronousSocketChannel asynchronousSocketChannel, TioServer tServer) {
        ShikuTioServer tioServer = null;

        try {
            try {
                tioServer = (ShikuTioServer) tServer;
                ImServerGroupContext serverGroupContext = (ImServerGroupContext) tioServer.getServerGroupContext();
                ImSessionContext sessionContext = null;
                if (1 == this.protocol) {
                    sessionContext = new TcpSessionContext();
                    ((ImSessionContext) sessionContext).setProtocolHandler(serverGroupContext.getTcpServerAioHandler());
                } else if (2 == this.protocol) {
                    sessionContext = new WsSessionContext();
                    ((ImSessionContext) sessionContext).setProtocolHandler(serverGroupContext.getWsServerAioHandler());
                }

                InetSocketAddress inetSocketAddress = (InetSocketAddress) asynchronousSocketChannel.getRemoteAddress();
                String clientIp = inetSocketAddress.getHostString();
                if (serverGroupContext.statOn) {
                    ((ServerGroupStat) serverGroupContext.groupStat).accepted.incrementAndGet();
                }

                asynchronousSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
                asynchronousSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 65536);
                asynchronousSocketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 65536);
                asynchronousSocketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
                ImServerChannelContext channelContext = new ImServerChannelContext(serverGroupContext, asynchronousSocketChannel);
                channelContext.groupContext = serverGroupContext;
                if (2 == this.protocol) {
                    if (serverGroupContext.sslConfig != null) {
                        try {
                            SslFacadeContext sslFacadeContext = new SslFacadeContext(channelContext);
                            channelContext.init(serverGroupContext, asynchronousSocketChannel);
                            if (serverGroupContext.isServer()) {
                                sslFacadeContext.beginHandshake();
                            }
                        } catch (Exception var19) {
                            log.error("在开始SSL握手时发生了异常", var19);
                            Tio.close(channelContext, "在开始SSL握手时发生了异常" + var19.getMessage());
                            return;
                        }
                    } else {
                        channelContext.init(serverGroupContext, asynchronousSocketChannel);
                    }
                } else {
                    channelContext.init(serverGroupContext, asynchronousSocketChannel);
                }

                channelContext.setClosed(false);
                channelContext.stat.setTimeFirstConnected(SystemTimer.currTime);
                channelContext.setServerNode(tioServer.getServerNode());
                serverGroupContext.ips.bind(channelContext);
                channelContext.setAttribute(sessionContext);
                boolean isConnected = true;
                boolean isReconnect = false;
                if (serverGroupContext.getServerAioListener() != null && !SslUtils.isSsl(channelContext.groupContext)) {
                    try {
                        serverGroupContext.getServerAioListener().onAfterConnected(channelContext, isConnected, isReconnect);
                    } catch (Throwable var18) {
                        log.error(var18.toString(), var18);
                    }
                }

                if (!tioServer.isWaitingStop()) {
                    ReadCompletionHandler readCompletionHandler = channelContext.getReadCompletionHandler();
                    ByteBuffer readByteBuffer = readCompletionHandler.getReadByteBuffer();
                    readByteBuffer.position(0);
                    readByteBuffer.limit(readByteBuffer.capacity());
                    asynchronousSocketChannel.read(readByteBuffer, readByteBuffer, readCompletionHandler);
                    return;
                }
            } catch (Throwable var20) {
                log.error("", var20);
            }

        } finally {
            if (tioServer.isWaitingStop()) {
                log.info("{}即将关闭服务器，不再接受新请求", tioServer.getServerNode());
            } else {
                this.serverSocketChannel.accept(tioServer, this);
            }

        }
    }

    @Override
    public void failed(Throwable exc, TioServer tioServer) {
        this.serverSocketChannel.accept(tioServer, this);
        log.error("[" + tioServer.getServerNode() + "]监听出现异常", exc);
    }
}
